package com.wuqing.mybatisredisdemo.config;

import cn.hutool.core.codec.Base64;
import org.apache.ibatis.cache.Cache;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;

import javax.annotation.PostConstruct;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * @author luwenhao
 * @create 2021/8/2
 *
 * Mybatis-Redis 二级缓存配置类
 */
public class MybatisRedisCache implements Cache {
    private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);

    private String id;

    private StringRedisTemplate redisTemplate = SpringContextHolder.getBean(StringRedisTemplate.class);

    /**
     * Reids 提供支持的序列化对象
     */
    private JdkSerializationRedisSerializer jdkSerializer = new JdkSerializationRedisSerializer();

    public MybatisRedisCache(String id) {
        if(Objects.isNull(id)){
            throw new IllegalArgumentException("Cache instances require an ID");
        }

        this.id = id;
    }

    @Override
    public String getId() {
        return id;
    }

    /**
     * 向 Reids 中添加元素
     * @param key Reids 中的 Key 值
     * @param value Redis 中存储的具体值
     */
    @Override
    public void putObject(Object key, Object value) {
        // 对 Null 值进行拦截
        if(! Objects.isNull(key)){
            try {
                byte[] serialize = jdkSerializer.serialize(value);
                String encode = Base64.encode(serialize);
                redisTemplate.opsForValue().set(key.toString(), encode, 2, TimeUnit.MINUTES);
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }

    /**
     * 根据存储时的 Key 去 Redis 中取出对应的值
     * @param key
     * @return Reids 中存储的具体值
     */
    @Override
    public Object getObject(Object key) {
        // 对 Null 值进行拦截
        if(Objects.isNull(key)){
            return null;
        }
        // 使用 StringRedisTemple 取出存储在缓存中的值。
        try {
            String redisKey = key.toString();
            String cacheValue = redisTemplate.opsForValue().get(redisKey);
            byte[] decode = Base64.decode(cacheValue);
            return jdkSerializer.deserialize(decode);
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 根据 Key 删除 Reids 中存储的对应元素
     * @param key
     * @return
     */
    @Override
    public Object removeObject(Object key) {
        // 对 NPE 进行拦截
        if(Objects.isNull(key)){
            return null;
        }

        return redisTemplate.delete(key.toString());
    }

    /**
     * 清空 Redis 中的值
     */
    @Override
    public void clear() {
        // 清空缓存的一种方案，删除当前数据库中的所有数据
        Set<String> keys = redisTemplate.keys("*");

        redisTemplate.delete(keys);
    }

    /**
     * 存储在缓存中的元素数量
     * @return
     */
    @Override
    public int getSize() {
        return 0;
    }



    @Override
    public ReadWriteLock getReadWriteLock() {
        return this.readWriteLock;
    }
}
